package com.dingpeikeji.quickdeer.modules.realsche.web;

import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.alipay.api.RefundFastpayByPlatformNopwdApi;
import com.alipay.model.RefundFastpayByPlatformNopwdReq;
import com.dingpeikeji.quickdeer.core.common.persistence.Page;
import com.dingpeikeji.quickdeer.core.common.web.BaseController;
import com.dingpeikeji.quickdeer.core.modules.orders.entity.TOrders;
import com.dingpeikeji.quickdeer.core.modules.orders.entity.TOrdersOut;
import com.dingpeikeji.quickdeer.core.modules.orders.entity.TOrdersPerson;
import com.dingpeikeji.quickdeer.core.modules.orders.service.TOrdersOutService;
import com.dingpeikeji.quickdeer.core.modules.orders.service.TOrdersPersonService;
import com.dingpeikeji.quickdeer.core.modules.payinfo.entity.TPayinfo;
import com.dingpeikeji.quickdeer.core.modules.realsche.entity.TRealsche;
import com.dingpeikeji.quickdeer.core.modules.sys.entity.User;
import com.dingpeikeji.quickdeer.core.modules.sys.utils.UserUtils;
import com.dingpeikeji.quickdeer.modules.base.web.FSysController;
import com.dingpeikeji.quickdeer.modules.realsche.service.FRealscheService;
import com.dingpeikeji.quickdeer.modules.sms.entity.Sms;
import com.dingpeikeji.quickdeer.modules.sms.service.SmsApi;
import com.dingpeikeji.quickdeer.modules.utils.ValidateTool;
import com.dingpeikeji.quickdeer.modules.wx.common.web.OAuth;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.tencent.WXPay;
import com.tencent.common.Configure;
import com.tencent.protocol.refund_protocol.RefundReqData;

/**
 * 预定线路
 *
 */
@Controller
@RequestMapping(value={"{channelType}/realsche","{channelType}/pu/realsche"})
public class FRealscheController extends BaseController{
	private String[] weekdays = new String[]{"日","一","二","三","四","五","六"};
	@Autowired
	private FRealscheService fRealscheService;
	@Autowired
	private TOrdersOutService tOrdersOutService;
	@Autowired
	private TOrdersPersonService tOrdersPersonService;
	
	
	
	/**
	 * 实际班次列表
	 * 
	 */
	@RequestMapping("list")
	public String list(@PathVariable String channelType, TRealsche realsche, Model model, HttpServletRequest request, HttpServletResponse response) throws ParseException{
		String viewPage = MessageFormat.format("modules/realsche/{0}RealscheList", channelType); // 视图

		// 数据校验
		
		List<String> messages = Lists.newArrayList();
		// 发车日期非空（默认当天），格式判断yyyy-MM-dd，不能小于今天
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		Date date = new Date();
		String today = sdf.format(date); // 当天日期字符串
		date = sdf.parse(today); // 今天日期，只保留yyyyMMdd部分
		model.addAttribute("today", today);
		
		String departdateStr = realsche.getDepartdateStr(); // 发车日期
		if (ValidateTool.isEmptyOrNull(departdateStr)) {
			realsche.setDepartdateStr(today);
		} else {
			try {
				Date departdate = sdf.parse(departdateStr);
				if(departdate.compareTo(date)<0){
					messages.add("发车日期不能小于今天");
				}
			} catch (Exception e) {
				messages.add("发车日期填写不正确");
			}
		}
		
		String boardaddr = realsche.getBoardaddr(); // 出发站ID
		String boardaddrName = realsche.getBoardaddrName(); // 出发站名称
		if (ValidateTool.isEmptyOrNull(boardaddr) || ValidateTool.isEmptyOrNull(boardaddrName)) {
			messages.add("请选择出发地");
		}
		String offaddr = realsche.getOffaddr(); // 目的站ID
		String offaddrName = realsche.getOffaddrName(); // 目的站名称
		if (ValidateTool.isEmptyOrNull(offaddr) || ValidateTool.isEmptyOrNull(offaddrName)) {
			messages.add("请选择目的地");
		}
		
		// 保存购票返程的出发地和目的地
		
		String boardaddrfc = offaddr; // 购票返程的出发地
		String offaddrfc = boardaddr; // 购票返程的目的地
		String boardaddrNamefc =  offaddrName; // 返程出发地名称
		String offaddrNamefc = boardaddrName; // 返程的目的地名称
		model.addAttribute("boardaddrfc", boardaddrfc);
		model.addAttribute("offaddrfc", offaddrfc);
		model.addAttribute("boardaddrNamefc", boardaddrNamefc);
		model.addAttribute("offaddrNamefc", offaddrNamefc);
		
		//  格式化出发日期，前一天、后一天
		
		getDateNavigation(model, request, sdf, date, departdateStr);
		
		if(messages.isEmpty()) {
			// 如果是当天，则不可查询当天过时的数据
			if(today.equals(departdateStr)) {
				realsche.setNowHHmm(new SimpleDateFormat("HH:mm").format(new Date()));
			}
			Page<TRealsche> page = fRealscheService.findPage(new Page<TRealsche>(request, response), realsche); 
			model.addAttribute("page", page);
		} else {
			addMessage(model, messages.toArray(new String[]{}));
		}
		
		// 根据当前日期，计算9天内的日期集合，作为查询条件
		
		getNineDayList(realsche, model, sdf, today, departdateStr);
		
		model.addAttribute("realsche", realsche); // 查询条件
		return viewPage;
	}

	/**
	 * 计算9天内的日期集合
	 * @param realsche
	 * @param model
	 * @param sdf
	 * @param today
	 * @param departdateStr
	 * @throws ParseException
	 */
	private void getNineDayList(TRealsche realsche, Model model, SimpleDateFormat sdf, String today,
			String departdateStr) throws ParseException {
		List<Map<String,String>> dayList = Lists.newArrayList();
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(sdf.parse(realsche.getDepartdateStr()));
		int leftday = calendar.get(Calendar.DAY_OF_YEAR) - Calendar.getInstance().get(Calendar.DAY_OF_YEAR);
		/*
		 * 如果选中的就是今天，则上一天不可选择；
		 * 即，如果不是今天，则有上一天。
		 */
		if(!today.equals(departdateStr)) {
			calendar.add(Calendar.DATE, -1);
			// 上一天
			model.addAttribute("dayListPrev", sdf.format(calendar.getTime()));
			calendar.add(Calendar.DATE, +1);
		} 
		calendar.add(Calendar.DATE, -4);
		for(int i=0; i<=8; i++) {
			Map<String,String> day = Maps.newHashMap();
			day.put("ymd", sdf.format(calendar.getTime()));
			day.put("md", (calendar.get(Calendar.MONTH)+1)+"月" + calendar.get(Calendar.DAY_OF_MONTH)+"日");
			day.put("week","星期"+weekdays[(calendar.get(Calendar.DAY_OF_WEEK)-1)]);
			/**
			 * 比方当前天是23号：
			 * 23号在1之前的位置，无不可选
			 * 23号在1的位置，无不可选
			 * 23号在2的位置，前1天不可选，此时相差3天 i<1
			 * 23号在3的位置，前2天不可选，此时相差2天 i<2
			 * 23号在4的位置，前3天不可选，此时相差1天 i<3
			 * 23号在5的位置，前4天不可选，此时相差0天 i<4
			 * 23号不可能出现在6的位置
			 */
			if(0<=leftday && leftday<=3 && i<(4-leftday)) { // 这时候才有不可选的日期，其他情况都是可选的日期
				day.put("old", "date-old");
			} else if(i==4) {
				day.put("checked", "date-checked");
			} else {
				day.put("normal", "date-normal");
			}
			/*
			 * 中间的位置必然是选中的日期
			 */
			if(i==5) {
				calendar.add(Calendar.DATE, +1);
				// 下一天
				model.addAttribute("dayListNext", sdf.format(calendar.getTime()));
				calendar.add(Calendar.DATE, -1);
			}
			dayList.add(day);
			calendar.add(Calendar.DATE, 1);
		}
		// 日期条件集合
		model.addAttribute("dayList", dayList);
	}

	/**
	 * 前一天、后一天
	 * @param model
	 * @param request
	 * @param sdf
	 * @param date
	 * @param departdateStr
	 * @throws ParseException
	 */
	private void getDateNavigation(Model model, HttpServletRequest request, SimpleDateFormat sdf, Date date, String departdateStr) throws ParseException {
		Date departdate = sdf.parse(departdateStr);
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(departdate);
		model.addAttribute("departdateWeek", new SimpleDateFormat("MM月dd日").format(departdate)+"星期"+weekdays[(calendar.get(Calendar.DAY_OF_WEEK)-1)]);
		calendar.add(Calendar.DAY_OF_YEAR, -1);
		Date preDate = calendar.getTime();
		calendar.add(Calendar.DAY_OF_YEAR, 2);
		Date nextDate = calendar.getTime();
		String preDateStr = preDate.compareTo(date)<0?"":sdf.format(preDate);
		String nextDateStr = sdf.format(nextDate);
		String preUrl = ""; // 前一天地址
		String nextUrl = ""; // 后一天地址
		String backPage = request.getRequestURI()+"?";
		@SuppressWarnings("unchecked")
		Map<String,String[]> param = request.getParameterMap();
		if(param!=null) {
			Set<String> keys = param.keySet();
			Iterator<String> it = keys.iterator();
			while(it.hasNext()){
				String key = it.next();
				String[] values = (String[])param.get(key);
				if(values != null) {
					String p = "&"+key+"=";
					if(key.equals("departdateStr")) {
						preUrl += p + preDateStr;
						nextUrl += p + nextDateStr;
					} else {
						for(int i=0;i<values.length;i++) {
							if(i!=values.length){
								p += values[i];
							} else {
								p += values[i]+",";
							}
						}
						preUrl += p;
						nextUrl += p;
					}
				}
			}
		}
		model.addAttribute("preUrl", preDateStr == ""? "javascript:;":(backPage+preUrl));
		model.addAttribute("nextUrl", backPage+nextUrl);
	}
	
	/**
	 * 详情页
	 * 
	 */
	@RequestMapping("details")
	public String details(@PathVariable String channelType, TRealsche realsche,String boardaddrfc,String offaddrfc, Model model){
		String viewPage = MessageFormat.format("modules/realsche/{0}RealscheDetails", channelType); // 视图
		TRealsche realsche2 = fRealscheService.getRealscheOrderById(realsche);
		model.addAttribute("query", realsche);
		model.addAttribute("realsche", realsche2);
		// 保存购票返程的出发地和目的地
		model.addAttribute("boardaddrfc", boardaddrfc);
		model.addAttribute("offaddrfc", offaddrfc);
		/*model.addAttribute("boardList", realsche2.getTRealscheBoardList());
		model.addAttribute("offList", realsche2.getTRealscheOffList());*/
		return viewPage;
	}
	/**
	 * 预定
	 */
	@RequestMapping("booking")
	public String booking(@PathVariable String channelType, TOrders orders, String departdateStr, String realboardid, String realoffid,String boardaddrfc,String offaddrfc,Model model, RedirectAttributes redirectAttributes,HttpServletRequest request){
		String redirctPage = "redirect:/"+channelType+"/realsche/details?repage&realscheid={0}&realboardid={1}&realoffid={2}&departdateStr={3}"; // 订单信息页
		String payWayPage = "redirect:/"+channelType+"/pay/payWay?orderid={0}&boardaddrfc={1}&offaddrfc={2}"; // 支付方式选择页
		if(channelType.equals("a")){
			// 后台的用户身份保存在安全框架中
			orders.setOrderuserid(UserUtils.getUser().getId());
		}
		if(channelType.equals("f")) {
			// 前台的用户身份保存在session中
			User user = (User) request.getSession().getAttribute(FSysController.FRONT_USER_IN_SESSION);
			orders.setOrderuserid(user.getId());
		}
		if(channelType.equals("wx")) {
			// 微信的用户身份保存在session中
			User user = (User)request.getSession().getAttribute(OAuth.SESSION_PUBUSER);
			orders.setOrderuserid(user.getId());
		}
		
		// ====================>>校验数据
		List<String> messages = Lists.newArrayList(); // 消息
		String purchasenum = orders.getPurchasenum(); // 车辆数
		if(ValidateTool.isEmptyOrNull(purchasenum)){
			messages.add("请选车辆数");
		} else if (!ValidateTool.isNonnegativeDigit(purchasenum)) {
			messages.add("车辆数量不正确");
		}
		String contacts = orders.getContacts(); // 联系人
		String payertel = orders.getPayertel(); // 联系电话
		String ordertype = orders.getOrdertype(); // 联系电话
		if(ValidateTool.isEmptyOrNull(contacts)){
			messages.add("请填写联系人");
		}
		if(ValidateTool.isEmptyOrNull(ordertype)){
			messages.add("未知用途的订单");
		}
		if(ValidateTool.isEmptyOrNull(payertel)){
			messages.add("请填写联系电话");
		} else if(!ValidateTool.isMobile(payertel)) {
			messages.add("联系电话不正确");
		}
		// ====================>>校验数据<<结束
		
		TRealsche realsche = new TRealsche();
		realsche.setRealscheid(orders.getRealscheid());
		realsche.setDepartdateStr(departdateStr);
		realsche.setRealboardid(realboardid);
		realsche.setRealoffid(realoffid);
		// 订单生成之前再判断下余票数量，有可能因为用户停留页面时间过长，导致余票不足
		realsche = fRealscheService.getRealscheOrderById(realsche);
		
		// 无需判断realsche为空，如果为空让页面报异常
		try {
			Integer leftSeats = Integer.parseInt(realsche.getLeftSeats());
			if(leftSeats==null || leftSeats<=0) {
				messages.add("对不起，余票不足，可能停留页面时间过长，请重新订票！");
			}
		} catch (NumberFormatException e) {
			messages.add("对不起，系统维护中，班次数据暂不可用！");
		}
		
		if (messages.isEmpty()) {
			String message = fRealscheService.saveOrder(orders, realsche);
			if(message!=null){
				messages.add(message);
			} else {
				//生成订单后保存乘客信息
				String[] passengers = request.getParameterValues("passenger");//姓名
				String[] certinos = request.getParameterValues("certino");//身份证号码
				for (int i=0;i<passengers.length;i++){
					TOrdersPerson orderPerson = new TOrdersPerson();
					orderPerson.setOrderid(Integer.valueOf(orders.getOrderid()));
					orderPerson.setPassenger(passengers[i]);
					orderPerson.setCertino(certinos[i]);
					orderPerson.setContel(payertel);
					tOrdersPersonService.save(orderPerson);
				}
				
				// 生成订单后调到支付页面
				return MessageFormat.format(payWayPage, orders.getOrderid(),boardaddrfc, offaddrfc);
			}
		}
		addMessage(redirectAttributes, messages.toArray(new String[]{}));
		return MessageFormat.format(redirctPage, ""+orders.getRealscheid(), ""+realboardid, ""+realoffid, departdateStr);
	}
	
	/**
	 * 退票选择数量页面
	 * @return
	 */
	@RequestMapping("backMoney")
	public String backMoney(@PathVariable String channelType, String orderid, Model model){
		String viewPage = MessageFormat.format("modules/realsche/{0}RealscheBackMoney", channelType); // 视图
		TOrders orders = fRealscheService.getOrders(orderid);
		model.addAttribute("orders", orders);
		return viewPage;
	}
	
	/**
	 * 退票
	 * @return
	 */
	@RequestMapping("doBackMoney")
	public String doBackMoney(@PathVariable String channelType, TOrders orders, RedirectAttributes redirectAttributes, HttpServletRequest request, HttpServletResponse response){
		String viewPage = MessageFormat.format("redirect:/{0}/pu/orders/orderList?repage&orderstatus={1}", channelType, TOrders.STATUS_PAY); // 视图
		TOrders torders = fRealscheService.getOrders(orders.getOrderid());
		// ==========>>数据校验
		List<String> messages = Lists.newArrayList(); // 消息
		Integer purchasenum = StringUtils.isEmpty(orders.getPurchasenum())?0:Integer.valueOf(orders.getPurchasenum());
		Integer childnum = StringUtils.isEmpty(orders.getChildnum())?0:Integer.valueOf(orders.getChildnum());
		Integer tpurchasenum = StringUtils.isEmpty(torders.getPurchasenum())?0:Integer.valueOf(torders.getPurchasenum());
		Integer tchildnum = StringUtils.isEmpty(torders.getChildnum())?0:Integer.valueOf(torders.getChildnum());
		if(purchasenum + childnum <= 0) {
			messages.add("退款数量至少为1张！");
		} else if(!(purchasenum <= tpurchasenum && childnum <= tchildnum)){
			messages.add("退票数量不正确！");
		} 
		// ==========>>数据校验<<结束
		boolean sendSms = false; // 是否发送短信
		if(messages.isEmpty()) {
			TPayinfo payinfo = torders.getPayinfo();
			if(payinfo!=null && payinfo.getDiscountid() != null){
				Map<String,Object> result = fRealscheService.proCmptReturn(orders);
				Integer returnflag = (Integer) result.get("returnflag");
				if(returnflag!=null&&returnflag==0){
					String payway = torders.getPayway();
					//批次号，必填，格式：当天日期[8位]+序列号[3至24位]，如：201603081000001
					String batch_no = new SimpleDateFormat("yyyyMMdd").format(new Date())+UUID.randomUUID().toString().replace("-", "").substring(0, 16);
					//退款笔数，必填，参数detail_data的值中，“#”字符出现的数量加1，最大支持1000笔（即“#”字符出现的数量999个）
					String batch_num = "1";
					Double money = (Double) result.get("returnmoney");
					//退款详细数据，必填，格式（支付宝交易号^退款金额^备注），多笔请用#隔开
					String detail_data = payinfo.getFlowno() // 流水号就是支付宝单号
							+"^"+money+"^"
							+orders.getPurchasenum()+","+orders.getChildnum(); // 退款数量
					if(payway.equals(TOrders.PAY_WAY_ALIPAY)){ // 支付宝支付
						String refund_date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
						
						try {
							RefundFastpayByPlatformNopwdReq req = new RefundFastpayByPlatformNopwdReq(batch_no, refund_date, batch_num, detail_data);
							new RefundFastpayByPlatformNopwdApi().execute(req, request, response);
							// 保存退款信息
							TOrdersOut orderOut = new TOrdersOut();
							orderOut.setOrderid(Integer.parseInt(orders.getOrderid()));
							orderOut.setBatchNo(batch_no);
							orderOut.setOutnum(Integer.parseInt(orders.getPurchasenum()));
							orderOut.setRtnmoney(money);
							orderOut.setOutchildnum(Integer.parseInt(orders.getChildnum()==null?"0":orders.getChildnum()));
							orderOut.setNotifyed(TOrdersOut.NOTIFED_NO);
							orderOut.setOutuserid(UserUtils.getUser().getId());
							orderOut.setRtnstatus(TOrdersOut.RTN_STATUS_FAIL);
							tOrdersOutService.save(orderOut);
							fRealscheService.proConfirmRtn(batch_no);
//							return null;
							messages.add("支付宝退票请求成功！");
							sendSms = true;
						} catch (Exception e) {
							messages.add("请求退款异常！");
						}
					}
					if(payway.equals(TOrders.PAY_WAY_WXPAY)){ // 微信支付
						String out_trade_no = "";
						for(int i=0;i<32-orders.getOrderid().length();i++){ // 补齐32位字符串
							out_trade_no+="0";
						}
						int moneyint = (int)(Double.valueOf(money)*100);
						out_trade_no+=orders.getOrderid();
						RefundReqData refundReqData = new RefundReqData(""//payinfo.getFlowno()
								, out_trade_no, ""
								, batch_no
								, (int)(Double.valueOf(torders.getDueamount())*100)
								, moneyint
								, Configure.getMchid()
								, "CNY");

							try {
								String responseString = WXPay.requestRefundService(refundReqData);
								// 保存退款信息
								TOrdersOut orderOut = new TOrdersOut();
								orderOut.setOrderid(Integer.parseInt(orders.getOrderid()));
								orderOut.setBatchNo(batch_no);
								orderOut.setOutnum(Integer.parseInt(orders.getPurchasenum()));
								orderOut.setRtnmoney(money);
								orderOut.setOutchildnum(Integer.parseInt(orders.getChildnum()==null?"0":orders.getChildnum()));
								orderOut.setNotifyed(TOrdersOut.NOTIFED_NO);
								orderOut.setOutuserid(UserUtils.getUser().getId());
								orderOut.setRtnstatus(TOrdersOut.RTN_STATUS_FAIL);
								tOrdersOutService.save(orderOut);
								fRealscheService.proConfirmRtn(batch_no);
								messages.add("微信退票请求成功！");
								sendSms = true;
							} catch (Exception e) {
								messages.add("请求退款异常！");
							}
					}
				} else {
					messages.add((String) result.get("returnmsg"));
				}
			} else {
				messages.add("订单暂未生效！");
			}
		}
		// 订车人申请退单成功后，收到平台短信
		if(sendSms){
			Sms sms = new Sms();
			sms.setMobile(torders.getPayertel());
			sms.setContent("【霞客约车】您购买的由"+torders.getOffice().getName()+"提供的用车订单（"+torders.getOrderid()+"）已取消，我们将根据预订规则将相应款项在3个工作日内返回您的支付账户。");
			try {
				SmsApi.sendSms(sms);
			} catch (Exception e) {
			}
		}
		addMessage(redirectAttributes, messages.toArray(new String[]{}));
		return viewPage;
	}
	
}
